<template>
  <div class="container">
    <!-- 原有内容包裹在logged-content中 -->
    <div class="logged-content">
      <!-- 在合适位置添加流式输出切换按钮 -->
      <!--   聊天界面头部   -->
      <div class="header connection-status" :class="connectionState">
        <div class="stream-toggle" style="left: 0;position: fixed;margin-left: 15px;cursor: pointer">
          <a-switch v-model:checked="isStream" size="small" />
          <span class="stream-label">{{ isStream ? '流式输出' : '完整输出' }}</span>
        </div>
        <span v-if="connectionState!=='connected'">{{ connectionState }}</span>
        <span v-else>若小智</span>
        <div v-if="userInfo?.token" style="right: 0;position: fixed;margin-right: 15px;color: red;cursor: pointer" @click="back"> 退出</div>
        <div v-else style="right: 0;position: fixed;margin-right: 15px;color: red;cursor: pointer" @click="toLogin"> 前往登录</div>
      </div>
      <!--  聊天内容区域  -->
      <div class="chat-area" ref="chatArea">
        <div v-for="(item,index) in messages" :key="item.id"
             :class="['message-wrapper', item.isUser ? 'user-message' : 'ai-message']">
          <a-avatar
            :class="['message-avatar', item.isUser ? 'user-avatar' : 'ai-avatar']"
          >{{ item.isUser ? userInfo?.name?.charAt(0) : '智' }}
          </a-avatar>
          <div class="message-content">
            <div class="message-text markdown-container"
                 :class="{ 'streaming': isStream && isLastMessage(index) && isSending}" :ref="el => setMarkdownRef(el, index)"  v-html="compiledMarkdown(item.content,item.isUser)">
            </div>
            <div :class="item.isUser?'user-name':'bot-name'">{{ item.timestamp }}</div>
          </div>
        </div>
        <!--    滚动到底部标识    -->
        <div ref="messagesEndRef" class="anchor-element"></div>
      </div>
      <!--  消息输入框    -->
      <div class="input-area">
        <a-textarea
          v-model:value="inputText"
          @pressEnter="handleSend"
          placeholder="输入消息..."
          :auto-size="{ minRows: 1, maxRows: 4 }"
          class="input"
          @keydown.enter.shift.exact.prevent
          @focus="handleInputFocus"
          @blur="handleInputBlur"
        />
        <a-button
          type="primary"
          v-prevent-reclick
          :disabled="isSending"
          class="send-button"
          @click="handleSend"
        >
          <template #icon>
            <SendOutlined />
          </template>
          发送
        </a-button>
      </div>
    </div>
  </div>
</template>

<script>
import { UserOutlined, RobotOutlined, SendOutlined } from '@ant-design/icons-vue'
import { message } from 'ant-design-vue'
import request from '@/util/request.js'
import { marked } from 'marked'
import hljs from 'highlight.js';

export default {
  components: {
    UserOutlined,
    RobotOutlined,
    SendOutlined
  },
  data() {
    return {
      clipboard: null,
      markdownRefs: [],
      // tempChat
      tempChat:"你好，我是一个聊天助手，很高兴和你聊天",
      // 用户信息
      userInfo: this.$store.state.userInfo,
      // 消息列表
      messages: [],
      // 输入消息
      inputText: '',
      // 下滑到底部
      messagesEndRef: null,
      // 新增WebSocket相关状态
      ws: null,
      // 连接状态
      connectionState: 'disconnected',
      // 重连相关状态
      reconnectAttempts: 0,
      maxReconnectAttempts: 5,
      // 登录相关数据
      isLoggedIn: false,
      // 聊天编号
      chatNo: '',
      // 是否流式输出
      isStream: true,
      // 流式输出相关状态
      currentStream: null,
      // 是否正在发送消息
      isSending: false
    }
  },
  watch: {
    // 监听消息列表滑动到底部
    // messages: {
    //   handler() {
    //     this.$nextTick(() => {
    //       this.scrollToBottom()
    //     })
    //   },
    //   deep: true
    // }
  },
  computed: {
    // 根据连接状态显示不同的状态文本
    statusText() {
      const states = {
        connecting: '连接中...',
        connected: '已连接',
        disconnected: '连接断开',
        reconnecting: `尝试重连 (${this.reconnectAttempts}/${this.maxReconnectAttempts})`
      }
      return states[this.connectionState]
    }
  },
  mounted: function() {
    if (this.userInfo?.token) {
      console.log('已登录')
      this.chatNo = this.$route.query.chatNo
      this.isLoggedIn = true
      this.getMemory(this.chatNo)
      this.initWebSocket(this.chatNo)
    } else {
      console.log('未登录')
      const tempChatNo = localStorage.getItem("tempChatNo")
      if (tempChatNo!==null) {
        this.chatNo = tempChatNo
        this.getMemory(this.chatNo)
      } else {
        this.chatNo = Date.now();
        localStorage.setItem("tempChatNo", "" + this.chatNo)
        this.messages.push({
          id: Date.now(),
          content: this.tempChat,
          isUser: false,
          timestamp: '小智'
        })
      }
      this.initWebSocket(this.chatNo)
    }
    this.observer = new ResizeObserver(() => {
      this.scrollToBottom()
    })
    this.observer.observe(this.$refs.chatArea)
  },
  // 组件销毁时取消监听
  beforeUnmount() {
    this.ws?.close()
    window.removeEventListener('online', this.handleNetworkChange)
    this.observer?.disconnect()
  },
  methods: {
    setMarkdownRef(el, index) {
      if (el) {
        this.markdownRefs[index] = el;
      }
    },
    isLastMessage(index) {
      // 是最后一条消息且是AI消息
      return index === this.messages.length - 1 && !this.messages[index].isUser
    },
    // 退出按钮
    back() {
      this.$router.push('/list')
    },
    // 前往登录
    toLogin() {
      this.$router.push('/login')
    },
    // 滑动到底部
    scrollToBottom() {
      requestAnimationFrame(() => {
        const container = this.$refs.chatArea
        const anchor = this.$refs.messagesEndRef
        if (!container || !anchor) return
// 多重保障滚动
        const scroll = () => {
          try {
            const targetY = anchor.offsetTop - container.offsetHeight + 100
            container.scrollTo({
              top: targetY,
              behavior: 'smooth'
            })
          } catch (e) {
            console.error('Scroll error:', e)
          }
        }
        scroll()
        // 多重保障滚动
        setTimeout(scroll, 150)
      })
    },
    // 获取最新消息
    getMemory(token) {
      const url = this.isLoggedIn ? '/memory/getMemoryByChatNo?chatNo=' + token : '/memory/getTempMemoryByChatNo?chatNo=' + token
      request.get(url).then(res => {
        if (res.data.code === 200) {
          if (res.data.data.length === 0){
            this.messages.push({
              id: Date.now(),
              content: this.tempChat,
              isUser: false,
              timestamp: '小智'
            })
          }
          res.data.data.forEach(data => {
            this.messages = [...this.messages, {
              id: Date.now() + 1,
              content: data.content,
              isUser: data.role === 'user',
              timestamp: data.role === 'user' ? this.userInfo?.name : '小智'
            }]
          })
          this.scrollToBottom()
        }
      })
    },
    // 初始化WebSocket连接
    initWebSocket(token) {
      this.connectionState = 'connecting'
      if (this.isLoggedIn){
        this.ws = new WebSocket(this.$store.state.wsUrl + token)
      }else {
        this.ws = new WebSocket(this.$store.state.wsTempUrl + token)
      }
      /*建立连接*/
      this.ws.onopen = () => {
        this.connectionState = 'connected'
        this.reconnectAttempts = 0
      }
      /*收到消息处理*/
      this.ws.onmessage = (event) => {
        if (this.isStream) {
          this.handleReceivedStream(event.data)
        } else {
          this.handleReceivedMessage(event.data)
        }
      }
      /*error处理*/
      this.ws.onerror = (error) => {
        console.error('WebSocket error:', error)
        this.connectionState = 'disconnected'
        this.isSending = false
      }
      /*关闭连接处理*/
      this.ws.onclose = (event) => {
        if (!event.wasClean) {
          this.handleReconnect()
        }
      }
    },
    // 处理接收消息
    handleReceivedMessage(data) {
      this.messages = [...this.messages, {
        id: Date.now() + 1,
        content: data,
        isUser: false,
        timestamp: new Date().toLocaleTimeString()
      }]
      this.isSending = false
    },
    // 处理接收消息——流失响应
    handleReceivedStream(data) {
      try {
        if (data === '设置成功' || data === '清除成功'){
          this.messages[this.messages.length - 1].content += data
          // 滑动
          this.scrollToBottom()
          this.isSending = false
          if (data==='清除成功'){
            location.reload()
          }
          return
        }
        // 如果是最后一条消息，更新整个内容
        if (data === '[DONE]') {
          // 滑动
          this.scrollToBottom()
          this.isSending = false
        } else {
          // 流式消息处理
          if (this.messages.length > 0 && !this.messages[this.messages.length - 1].isUser) {
            // 追加到最后一条AI消息
            this.messages[this.messages.length - 1].content += data
          } else {
            // 新建AI消息
            this.messages.push({
              id: Date.now(),
              content: data,
              isUser: false,
              timestamp: '小智'
            })
          }
        }
        // 触发视图更新
        this.$forceUpdate()
      } catch (error) {
        console.error('Error processing message:', error)
      }
    },
    // 发送消息
    async handleSend(e) {
      if (e?.shiftKey || !this.inputText.trim() || this.isSending) return

      const userMessage = {
        id: Date.now(),
        content: this.inputText,
        isUser: true,
        timestamp: new Date().toLocaleTimeString()
      }

      this.messages = [...this.messages, userMessage]
      this.inputText = ''

      if (this.isStream) {
        // 添加一个空的AI消息占位
        const aiMessage = {
          id: Date.now() + 1,
          content: '',
          isUser: false,
          timestamp: new Date().toLocaleTimeString()
        }
        this.messages = [...this.messages, aiMessage]
      }
      this.isSending = true
      // 滑动
      this.scrollToBottom()
      // 通过WebSocket发送
      if (this.ws?.readyState === WebSocket.OPEN) {
        this.ws.send(JSON.stringify({
          chatNo: this.chatNo,
          content: userMessage.content,
          isStream: this.isStream
        }))
      } else {
        message.error('连接未就绪，请稍后重试')
      }
    },
    // 重连逻辑
    handleReconnect() {
      this.isSending = false
      if (this.reconnectAttempts < this.maxReconnectAttempts) {
        this.connectionState = 'reconnecting'
        this.reconnectAttempts++
        setTimeout(() => this.initWebSocket(this.chatNo), Math.min(5000, 1000 * this.reconnectAttempts))
      } else {
        this.connectionState = 'disconnected'
      }
    },

    // 网络变化处理
    handleNetworkChange() {
      if (navigator.onLine && this.connectionState === 'disconnected') {
        this.initWebSocket(this.chatNo)
      }
    },
    handleInputFocus() {
      // 增加布局刷新次数
      this.$nextTick(() => {
        this.scrollToBottom()
        setTimeout(this.scrollToBottom, 200)
      })
    },
    handleInputBlur() {
      this.$nextTick(() => {
        setTimeout(this.scrollToBottom, 200) // 增加延迟处理键盘收起动画
      })
    },
    /*markdown*/
    compiledMarkdown(content,isUser) {
      if (!content || typeof content !== 'string') return '';

      // 用户不进行渲染
      if (isUser){
        return marked(content)
      }

      const containerId = 'md-' + Math.random().toString(36).substr(2, 9);
      const renderer = new marked.Renderer();

      renderer.code = (code, language) => {
        const lang = (language || '').match(/\S*/)[0];
        const id = 'code-' + Math.random().toString(36).substr(2, 9);
        const validLang = hljs.getLanguage(lang) ? lang : 'plaintext';
        const highlighted = hljs.highlight(code.text, { language: validLang }).value;

        return `
        <div class="code-block">
          <pre><code id="${id}" class="hljs ${validLang}">${highlighted}</code></pre>
          <button class="copy-btn" data-target="#${id}" title="复制代码">
            复制代码
          </button>
        </div>
      `;
      };

      marked.setOptions({
        renderer,
        highlight: (code, lang) => {
          if (lang && hljs.getLanguage(lang)) {
            return hljs.highlight(code, { language: lang }).value;
          }
          return hljs.highlightAuto(code).value;
        }
      });
      this.setupClipboard()
      return `
        <div class="markdown-container" id="${containerId}">
          ${marked(content)}
          <button class="copy-container-btn" data-container="#${containerId}" title="复制全部内容">
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
              <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
              <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
            </svg>
            复制全部
          </button>
        </div>
      `;
    },
    setupClipboard() {
      // 移除旧的事件监听
      const chatArea = this.$refs.chatArea;
      if (!chatArea) return;

      // 处理复制代码块
      chatArea.addEventListener('click', async (e) => {
        if (e.target.classList.contains('copy-btn')) {
          const target = e.target.getAttribute('data-target');
          const code = document.querySelector(target)?.textContent || '';
          await this.copyToClipboard(code, e.target);
        }

        // 处理复制整个容器
        if (e.target.closest('.copy-container-btn')) {
          const btn = e.target.closest('.copy-container-btn');
          const containerId = btn.getAttribute('data-container');
          const container = document.querySelector(containerId);
          if (container) {
            // 获取纯净文本（去除按钮文本）
            const text = container.textContent
              .replace(/复制代码/g, '')
              .replace(/复制全部/g, '')
              .replace(/✓ 已复制/g, '')
              .trim();
            await this.copyToClipboard(text, btn);
          }
        }
      });
    },

    async copyToClipboard(text, button) {
      try {
        // 方法1：现代 Clipboard API
        if (navigator.clipboard?.writeText) {
          await navigator.clipboard.writeText(text);
          this.showCopyFeedback(button, true);
          return;
        }

        // 方法2：旧版浏览器降级方案
        const textarea = document.createElement('textarea');
        textarea.value = text;
        textarea.style.position = 'fixed';
        textarea.style.opacity = '0';
        document.body.appendChild(textarea);
        textarea.select();

        const success = document.execCommand('copy');
        document.body.removeChild(textarea);

        if (success) {
          this.showCopyFeedback(button, true);
        } else {
          throw new Error('复制命令失败');
        }
      } catch (err) {
        console.error('复制失败:', err);
        this.showCopyFeedback(button, false);
        // 终极降级方案 - 提示用户手动复制
        this.showManualCopyPrompt(text);
      }
    },

    showCopyFeedback(button, isSuccess) {
      if (!button) return;

      const originalHTML = button.innerHTML;
      button.innerHTML = isSuccess
        ? '<span style="color:green">✓ 已复制</span>'
        : '<span style="color:red">✗ 失败</span>';

      setTimeout(() => {
        button.innerHTML = originalHTML;
      }, 2000);
    },

    showManualCopyPrompt(text) {
      const shouldCopy = confirm('一键复制不可用，请手动选择以下文本后按Ctrl+C复制：\n\n' + text);
      if (shouldCopy) {
        this.selectTextForManualCopy(text);
      }
    },

    selectTextForManualCopy(text) {
      const pre = document.createElement('pre');
      pre.style.whiteSpace = 'pre-wrap';
      pre.textContent = text;
      pre.style.position = 'fixed';
      pre.style.left = '-9999px';
      document.body.appendChild(pre);

      const range = document.createRange();
      range.selectNode(pre);
      window.getSelection()?.removeAllRanges();
      window.getSelection()?.addRange(range);

      setTimeout(() => {
        document.body.removeChild(pre);
      }, 100);
    }
  }
}
</script>

<style scoped>
.header {
  z-index: 100;
  display: flex;
  justify-content: center;
  top: 0;
  left: 0;
  right: 0;
  padding: 15px;
  background: white;
  box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.1);
}

/* 保持与React版本相同的样式 */
.container {
  height: calc(100vh - env(safe-area-inset-bottom));
  display: flex;
  flex-direction: column;
  background-color: #f0f2f5;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}

.chat-area {
  height: calc(100vh - 120px) !important;
  overflow-y: scroll;
  scroll-behavior: smooth;
  flex: 1;
  padding: 20px;
  background: linear-gradient(180deg, #f8f9fa 0%, #ffffff 100%);
  overflow-anchor: none; /* 禁用浏览器自动滚动 */
}

/* 添加锚点元素样式 */
.anchor-element {
  overflow-anchor: auto;
  height: 1px;
}

/* 新增流式切换按钮样式 */
.stream-toggle {
  display: flex;
  align-items: center;
  padding: 5px 10px;
  border-radius: 20px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  cursor: pointer;
  z-index: 1000;
}

.stream-label {
  margin-left: 8px;
  font-size: 12px;
  color: #666;
}

.input-area {
  display: flex;
  border-top: 1px solid #e8e8e8;
  position: fixed;
  left: 0;
  right: 0;
  padding: 15px;
  background: white;
  box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.1);
  bottom: env(safe-area-inset-bottom); /* 适配iPhone底部安全区域 */
}

.input {
  flex: 1;
  margin-right: 10px;
  border-radius: 20px;
  padding: 12px 20px;
}

.send-button {
  border-radius: 20px;
  padding: 0 25px;
  height: 40px;
}

.message-wrapper {
  display: flex;
  align-items: flex-start;
  margin-bottom: 10px;
}

.user-message {
  justify-content: right;
  flex-direction: row-reverse; /* 反转头像和内容的位置 */
}

.ai-message {
  justify-content: flex-start; /* AI 消息靠左 */
}

.message-content {
  max-width: 70%;
  margin: 0 10px;
  border-radius: 8px;
}

.message-text {
  padding: 12px 18px;
  border-radius: 20px;
  background: #fff;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  position: relative;
}

.user-avatar {
  background-color: #1890ff;
  align-self: flex-end;
  text-align: right;
  margin-left: 10px;
}

.ai-avatar {
  margin-right: 10px;
  background-color: #52c41a;
  text-align: left;
}

.user-name {
  font-size: 12px;
  color: #999;
  margin-top: 4px;
  text-align: right;
}

.bot-name {
  font-size: 12px;
  color: #999;
  margin-top: 4px;
  text-align: left;
}

/* 添加连接状态样式 */
.connection-status {
  padding: 8px;
  height: 45px;
  text-align: center;
  align-items: center;
  font-size: 16px;
  background: #ffccc7;
  color: #000;
  transition: all 0.3s;
}

.connection-status.connected {
  background: #b7eb8f;
}

.connection-status.connecting {
  background: #fffbe6;
}

.connection-status.reconnecting {
  background: #ffe58f;
}

h2 {
  text-align: center;
  margin-bottom: 30px;
  color: #1890ff;
}

/* 添加流式消息的打字机效果 */
.message-text.streaming {
  border-right: 2px solid #1890ff;
  animation: blink-caret 0.75s step-end infinite;
}

@keyframes blink-caret {
  from, to {
    border-color: transparent
  }
  50% {
    border-color: #1890ff
  }
}

@media (max-width: 768px) {
  .container {
    height: 100% !important;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
  }

  .chat-area {
    height: calc(100vh - 80px) !important;
    padding-bottom: 0 !important;
    overflow-y: scroll;
    scroll-behavior: smooth;
  }
  .input-area {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    padding: 15px;
    background: white;
    box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.1);
  }

  .message-content {
    max-width: 85%;
  }

  .message-text {
    padding: 10px 15px;
    font-size: 16px; /* 增大字体 */
  }

  .input {
    padding: 10px 15px;
    min-height: 48px; /* 增大触控区域 */
  }

  .send-button {
    padding: 0 20px;
    height: 48px;
  }

  /* 手机端隐藏头像 */
  .user-avatar,
  .ai-avatar {
    display: none;
  }

  /* 横屏适配 */
  @media (orientation: landscape) {
    .container {
      height: 80vh;
    }
  }

  .chat-area {
    padding-bottom: 80px !important; /* 给输入区域留出空间 */
  }

  /* 优化键盘弹出时的视口高度 */
  .container {
    height: 100vh;
    max-height: -webkit-fill-available;
  }

  /* 新增移动端优化样式 */
  .message-text {
    word-break: break-word;
    line-height: 1.5;
  }

  .input {
    transition: all 0.3s;
    -webkit-overflow-scrolling: touch; /* 移动端滚动优化 */
  }

  .send-button:active {
    transform: scale(0.95); /* 点击反馈 */
  }

  /* 防止移动端输入法遮挡 */
  @media (max-height: 600px) {
    .chat-area {
      padding-bottom: 80px;
    }
  }
}

:deep(p) {
  margin: 0;
}

/* 表格样式 - 保持原有布局 */
:deep(table) {
  display: block;
  overflow-x: auto; /* 启用横向滚动 */
  width: auto; /* 自动宽度 */
  min-width: 100%; /* 最小宽度为容器宽度 */
  border-collapse: collapse;
  table-layout: auto; /* 自动列宽 */
  margin: 1em 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 0.9em;
  border: 1px solid #e1e4e8;
}

:deep(table thead th) {
  background-color: #f8f9fa;
  font-weight: 600;
  text-align: center;
  padding: 12px 15px;
  border-bottom: 2px solid #d0d7de;
  border-right: 1px solid #e1e4e8;
}

/* 移除最后一列的右侧边框 */
:deep(table thead th:last-child ) {
  border-right: none;
}

/* 表格单元格样式 - 添加所有边框 */
:deep(table td ) {
  padding: 10px 15px;
  border-bottom: 1px solid #e1e4e8;
  border-right: 1px solid #e1e4e8;
  vertical-align: top;
  white-space: nowrap; /* 防止内容换行 */
}

/* 移除最后一列的右侧边框 */
:deep(table td:last-child) {
  border-right: none;
}

/* 最后一行不需要底部边框 */
:deep(table tr:last-child td) {
  border-bottom: none;
}

/* 斑马条纹效果 - 可选 */
:deep(table tbody tr:nth-child(odd) ) {
  background-color: #fafbfc;
}

/* 代码样式 */
:deep(table code ) {
  background-color: #f6f8fa;
  padding: 0.2em 0.4em;
  border-radius: 3px;
  font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace;
  font-size: 0.85em;
  border: 1px solid #e1e4e8; /* 代码块边框 */
}

/* 悬停效果 */
:deep(table tbody tr:hover ) {
  background-color: #f0f3f6;
}

:deep(.code-block-wrapper) {
  position: relative;
  margin: 1em 0;
}
:deep(.copy-btn) {
  position: absolute;
  top: 8px;
  right: 8px;
  padding: 2px 8px;
  background: #888585;
  border: none;
  border-radius: 3px;
  cursor: pointer;
  opacity: 0.7;
  transition: opacity 0.2s;
  font-size: 12px;
}

:deep(.copy-btn:hover) {
  opacity: 1;
  background: #d0d0d0;
}

/* 在 <style> 部分添加以下内容 */
:deep(.copy-container-btn) {
  position: absolute;
  bottom: -30px;
  right: 0;
  padding: 4px 8px;
  background: #f0f0f0;
  border: 1px solid #ddd;
  border-radius: 4px;
  cursor: pointer;
  font-size: 12px;
  display: flex;
  align-items: center;
  gap: 4px;
  transition: all 0.2s;
}

:deep(.copy-container-btn:hover ){
  background: #e0e0e0;
}

:deep(.copy-container-btn svg) {
  width: 14px;
  height: 14px;
}

/* 调整代码块复制按钮位置 */
:deep(.code-block) {
  position: relative;
}

:deep(.code-block .copy-btn) {
  position: absolute;
  top: 8px;
  right: 8px;
  padding: 2px 8px;
  background: #e8e8e8;
  border: none;
  border-radius: 3px;
  cursor: pointer;
  font-size: 12px;
}
</style>